unit QBData;

interface

{$I QBuilderVerCtrl.inc}

uses
  {$IFDEF VCL16}
    Winapi.Windows,
    Vcl.Grids,
    Vcl.StdCtrls,
    System.Classes,
    Vcl.Controls,
    Vcl.ComCtrls,
    Vcl.Forms,
    System.SysUtils,
    Winapi.Messages,
    Vcl.Menus,
    Vcl.Buttons,
    Vcl.Extctrls,
    Vcl.Graphics,
  {$ELSE}
    Windows,
    Grids,
    StdCtrls,
    Classes,
    Controls,
    ComCtrls,
    Forms,
    SysUtils,
    Messages,
    Menus,
    Buttons,
    Extctrls,
    Graphics,
  {$ENDIF}
  QBStringTypes,
  {$IFDEF USE_DEVEXPRESS}
    cxTL,
  {$ENDIF}
  QBParser;

const
  sEmpty = '                                                                ';
  iMaxControlTextLen = 60;

type

  TQBSelectEvent = procedure(const AFieldName, AAggregate, AFieldAlias,
    AFieldData: aqbString; ChangeState, InsertQuery, GroupBy: Boolean) of object;

  TQBChangeFieldDataEvent = procedure(const FieldName, FieldData: aqbString) of object;

{$IFNDEF   USE_DEVEXPRESS}
  TQBDataGrid = class(TStringGrid)
  private
    FFields: TaqbStrings;
    FAggregateCombo: TComboBox;
    FDragItem: Pointer;
    FNameEdit: TEdit;
    FPopupMenu: TPopupMenu;
    FOnSelectField: TQBSelectEvent;
    FOnUnselectField: TQBSelectEvent;
    FOnDeleteField: TQBSelectEvent;
    FOnChangeFieldData: TQBChangeFieldDataEvent;
    procedure SetFields(const Value: TaqbStrings);
    procedure HandleStringKeyDown(Sender: TObject; var Key: Word; Shift:
      TShiftState);
    procedure HandleStringDblClick(Sender: TObject);
    procedure HandleEditText(ACol, ARow: Longint);
    procedure HandleSetCellText(Sender: TObject);
    procedure HandleCellKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure HandleDeleteCurrentRow(Sender: TObject);
    procedure HandleDragOver(Sender, Source: TObject; X, Y: Integer; State:
      TDragState; var Accept: Boolean);
    procedure HandleDragDrop(Sender, Source: TObject; X, Y: Integer);
  protected
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ClearGrid;
    procedure CheckField(FieldDef: TQBFieldDef);
    procedure UnCheckField(FieldDef: TQBFieldDef);
    procedure ChangeAlias(const NewName, OldName: aqbString);
    property Fields: TaqbStrings read FFields write SetFields;
    property OnSelectField: TQBSelectEvent read FOnSelectField write
      FOnSelectField;
    property OnUnselectField: TQBSelectEvent read FOnUnselectField write
      FOnUnselectField;
    property OnDeleteField: TQBSelectEvent read FOnDeleteField
      write FOnDeleteField;
    property OnChangeFieldData: TQBChangeFieldDataEvent
      read FOnChangeFieldData write FOnChangeFieldData;
  end;
{$ELSE}
  TQBDataGrid = class(TcxTreeList)
  private
    FFields: TaqbStrings;
    FOnSelectField: TQBSelectEvent;
    FOnUnselectField: TQBSelectEvent;
    FOnDeleteField: TQBSelectEvent;
    FDragItem: Pointer;
    FPopupMenu: TPopupMenu;
    FOnChangeFieldData: TQBChangeFieldDataEvent;
    FPrevSrcName: aqbString;

    procedure SetFields(const Value: TaqbStrings);

    procedure HandleEditing(Sender: TObject; AColumn: TcxTreeListColumn; var Allow: Boolean);
    procedure HandleEdited(Sender: TObject; AColumn: TcxTreeListColumn);
    procedure HandleDeleteCurrentRow(Sender: TObject; ANode: TcxTreeListNode);
    procedure HandleAfterSorting(Sender: TObject);
    procedure HandleDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
    procedure HandleDragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure HandleDeleteRow(Sender: TObject);
    procedure Clear;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ClearGrid;
    procedure ChangeAlias(const NewName, OldName: aqbString);
    procedure CheckField(FieldDef: TQBFieldDef);
    procedure UnCheckField(FieldDef: TQBFieldDef);
    property Fields: TaqbStrings read FFields write SetFields;
    property OnSelectField: TQBSelectEvent read FOnSelectField write
      FOnSelectField;
    property OnUnselectField: TQBSelectEvent read FOnUnselectField write
      FOnUnselectField;
    property OnDeleteField: TQBSelectEvent read FOnDeleteField
      write FOnDeleteField;
    property OnChangeFieldData: TQBChangeFieldDataEvent
      read FOnChangeFieldData write FOnChangeFieldData;
  end;
{$ENDIF}

  TQBQueryLabel = class(TLabel)
  private
    FText: aqbString;
  protected
    procedure SetText(const Value: aqbString);
  public
    constructor Create(AOwner: TComponent); override;
    property Text: aqbString read FText write SetText;
  end;

  TQBDataType = (dtInsert, dtUpdate);

  TQBDataPanel = class(TWinControl)
  private
    FDataType: TQBDataType;
    FPanel: TPanel;
    FDataFromQuery: TLabel;
    FQueryLabel: TQBQueryLabel;
    FGrid: TQBDataGrid;
    FParser: TQBSelectParser;
    FQueryMenu: TPopupMenu;
    procedure SetParser(const Value: TQBSelectParser);
    procedure SetDataType(const Value: TQBDataType);
  protected
    procedure DeleteQuery(Sender: TObject);
    procedure HandleQueryLabelMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    constructor Create(AOwner: TComponent); override;
    procedure Clear;
    procedure RefreshFields;
    property Grid: TQBDataGrid read FGrid;
    property Parser: TQBSelectParser read FParser write SetParser;
    property DataGrid: TQBDataGrid read FGrid;
    property DataType: TQBDataType read FDataType write SetDataType;
  end;

implementation

uses
  QBWindow,
  QBFloatPanel,
  QBFloatTable,
  QBResource,
  {$IFDEF USE_DEVEXPRESS}
    CxControls,
    cxDropDownEdit,
    QBDialogs,
  {$ENDIF}
  QBUtils;

{$IFNDEF USE_DEVEXPRESS}
{ TQBDataGrid }
procedure TQBDataGrid.ClearGrid;
begin
  RowCount := 2;
  Cells[0, 1] := '';
  Cells[1, 1] := '';
end;

constructor TQBDataGrid.Create(AOwner: TComponent);
var
  MenuItem: TMenuItem;
begin
  if not (AOwner is TWinControl) then
    raise Exception.Create(rsDataInvalidGridParent);
  inherited;
  Parent := AOwner as TWinControl;
  ParentFont := True;
  Align := alCLient;
  Ctl3D := false;
  ControlStyle := ControlStyle + [csDisplayDragImage];
  ColCount := 2;
  FixedCols := 0;
  RowCount := 2;
  FixedRows := 1;
  ScrollBars := ssVertical;
  DefaultRowHeight := 20;
  Options := Options - [goRangeSelect] + [goDrawFocusSelected];
  DragKind := dkDrag;
  DragMode := dmManual;
  OnKeyDown := HandleStringKeyDown;
  OnDblClick := HandleStringDblClick;
  OnDragOver := HandleDragOver;
  OnDragDrop := HandleDragDrop;
  Cells[0, 0] := rsDataSourceFieldName;
  Cells[1, 0] := rsDataValueOfField;

  FAggregateCombo := TComboBox.Create(AOwner);
  FAggregateCombo.Parent := AOwner as TWinControl;
  FAggregateCombo.Visible := false;
  FAggregateCombo.Height := 100;
  FAggregateCombo.OnExit := HandleSetCellText;
  FAggregateCombo.OnKeyDown := HandleCellKeyDown;
  FAggregateCombo.Style := csDropDownList;

  FNameEdit := TEdit.Create(AOwner);
  FNameEdit.Parent := AOwner as TWinControl;
  FNameEdit.Visible := false;
  FNameEdit.Height := DefaultRowHeight;
  FNameEdit.OnExit := HandleSetCellText;
  FNameEdit.OnKeyDown := HandleCellKeyDown;

  FPopupMenu := TPopupMenu.Create(Self);
{$IFDEF VCL5}
  FPopupMenu.AutoHotkeys := maManual;
{$ENDIF}
  FPopupMenu.AutoPopup := true;
  MenuItem := TMenuItem.Create(Self);
  MenuItem.Caption := rsDataDeleteCurrentRow;
  MenuItem.OnClick := HandleDeleteCurrentRow;
  FPopupMenu.Items.Add(MenuItem);
  PopupMenu := FPopupMenu;

  FFields := TaqbStringList.Create();
end;

destructor TQBDataGrid.Destroy;
begin
  FFields.Free();
  inherited Destroy();
end;

procedure TQBDataGrid.Resize;
begin
  inherited Resize();
  ColWidths[0] := round(ClientWidth * 0.4);
  ColWidths[1] := ClientWidth - ColWidths[0] - 2;
end;

procedure TQBDataGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  NewRow, NewCol: Integer;
begin
  inherited;
  if ssLeft in Shift then
  begin
    MouseToCell(X, Y, NewCol, NewRow);
    if (NewRow > 0) and (NewRow < RowCount - 1) then
      BeginDrag(false, 1);
  end;
end;

procedure TQBDataGrid.HandleStringKeyDown(Sender: TObject; var Key: Word; Shift:
  TShiftState);
begin
  if Key = VK_RETURN then
    HandleEditText(Col, Row);
  if (Key = VK_DELETE) and (ssCtrl in Shift) then
  begin
    if MessageBox(Handle, PChar(rsDataSureWantDeleteRow),
      PChar(rsDataConfirmation),
      MB_ICONQUESTION or MB_YESNO) = IDNO then
      Exit;
    HandleDeleteCurrentRow(Self);
  end;
end;

procedure TQBDataGrid.HandleStringDblClick(Sender: TObject);
begin
  HandleEditText(Col, Row);
end;

procedure TQBDataGrid.HandleEditText(ACol, ARow: Longint);
var
  Rect: TRect;
begin
  if ACol = 1 then
  begin //choose agregative function
    Rect := CellRect(ACol, ARow);
    MapWindowPoints(Handle, Parent.Handle, Rect, 2);
    FNameEdit.Left := Rect.Left;
    FNameEdit.Width := Rect.Right - Rect.Left + 1;
    FNameEdit.Top := Rect.Top;
    FNameEdit.Text := Cells[ACol, ARow];
    FNameEdit.Visible := true;
    FNameEdit.SetFocus;
  end
  else
  begin
    Rect := CellRect(ACol, ARow);
    MapWindowPoints(Handle, Parent.Handle, Rect, 2);
    FAggregateCombo.Items.Assign(FFields);
    FAggregateCombo.Left := Rect.Left;
    FAggregateCombo.Width := Rect.Right - Rect.Left + 1;
    FAggregateCombo.Top := Rect.Top;
    FAggregateCombo.Text := Cells[ACol, ARow];
    FAggregateCombo.Visible := true;
    FAggregateCombo.SetFocus;
  end;
end;

procedure TQBDataGrid.HandleSetCellText(Sender: TObject);
var
  I: integer;
  Found: boolean;
begin
  TControl(Sender).Visible := false;
  if Sender is TComboBox then
  begin
    if ((Sender as TComboBox).Text = Cells[Col, Row]) and 
      (Trim(Cells[Col, Row]) <> '') then
      Exit;
  
    Found := False;
    for I := 1 to RowCount - 1 do
    begin
      Found := (I <> Row) and (Cells[0, I] = (Sender as TComboBox).Text) and 
        (Trim((Sender as TComboBox).Text) <> '');
      if Found then
        Exit;
    end;
    
    if Assigned(FOnUnselectField) then
      FOnUnselectField(Cells[0, Row], '', '', Cells[1, Row], True, False, False);
    Cells[Col, Row] := (Sender as TComboBox).Text;
    if Assigned(FOnSelectField) then
      FOnSelectField(Cells[0, Row], '', '', Cells[1, Row], True, False, False);
  end
  else
    if Sender is TEdit then
    begin
      Cells[Col, Row] := TEdit(Sender).Text;
      if Assigned(FOnChangeFieldData) then
        FOnChangeFieldData(Cells[0, Row], Cells[1, Row]);
    end;
  if (Col = 0) and (Row + 1 = RowCount) and (Cells[Col, Row] <> '') then
  begin //Add new Row
    RowCount := RowCount + 1;
    Cells[0, RowCount - 1] := '';
    Cells[1, RowCount - 1] := '';
  end;
  SetFocus;
end;

procedure TQBDataGrid.HandleCellKeyDown(Sender: TObject; var Key: Word; Shift:
  TShiftState);
begin
  if Key = VK_RETURN then
  begin
    (Sender as TControl).Visible := false;
  end;
  if Key = VK_ESCAPE then
  begin
    if (Sender is TCombobox) then
    begin
      (Sender as TCombobox).OnExit := nil;
      (Sender as TControl).Visible := false;
      (Sender as TCombobox).OnExit := HandleSetCellText;
    end
    else
    begin
      (Sender as TEdit).OnExit := nil;
      (Sender as TControl).Visible := false;
      (Sender as TEdit).OnExit := HandleSetCellText;
    end;
    SetFocus;
  end;
end;

procedure TQBDataGrid.HandleDeleteCurrentRow(Sender: TObject);
var
  FieldName, Data: aqbString;
  I: integer;
  Found: boolean;
begin
  if Row + 1 = RowCount then
    raise Exception.Create(rsDataCantDeleteLastRow);
  Found := False;
  for I := 1 to RowCount - 1 do
  begin
    //    Found := (I <> Row) and (Cells[2, I] = Cells[2, Row]) and (Trim(Cells[1, I]) = '');
    Found := (I <> Row) and (Cells[0, I] = Cells[0, Row]);
    if Found then
      Break;
  end;
  FieldName := Cells[0, Row];
  Data := Cells[1, Row];
  DeleteRow(Row);
  if Assigned(FOnDeleteField) then
    FOnDeleteField(FieldName, '', '', Data, not Found, False, False);
end;

procedure TQBDataGrid.HandleDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
var
  NewRow, NewCol: Integer;
  Tbl: TQBFloatObject;
begin
  Accept := false;
  MouseToCell(X, Y, NewCol, NewRow);
  if Source = Sender then
  begin
    if (NewRow > 0) and (NewRow < RowCount - 1) then
      Accept := true;
  end;
  if not (Source is TQBWorkArea) then
    Exit;
  Tbl := TQBFloatObject(TQBWorkArea(Source).SelectionObject);
  if not (Tbl is TQBTable) then
    Exit;
  FDragItem := (Tbl as TQBTable).CurrentItem;
  if FDragItem = nil then
    Exit;
  if NewRow = 0 then
    Exit;
  Accept := true;
end;

procedure TQBDataGrid.HandleDragDrop(Sender, Source: TObject; X, Y: Integer);
var
  Item: TQBListItem;
  NewRow, NewCol: Integer;
  TableName: aqbString;
begin
  MouseToCell(X, Y, NewCol, NewRow);
  if NewCol = -1 then
    NewCol := 2;
  if NewRow = -1 then
    NewRow := RowCount - 1;
  if Source = Sender then
  begin
    TableName := ExtractTableName(Cells[0, Row],
      TQBDataPanel(Owner).Parser.Scanner.IdentQuote,
      TQBDataPanel(Owner).Parser.Scanner.GetQuotePair(
      TQBDataPanel(Owner).Parser.Scanner.IdentQuote));
    MoveRow(Row, NewRow);
    Exit;
  end;
  Col := NewCol;
  Row := NewRow;
  if Row + 1 >= RowCount then
  begin
    RowCount := RowCount + 1;
    Cells[0, RowCount - 1] := '';
    Cells[1, RowCount - 1] := '';
  end
  else if Assigned(FOnUnSelectField) then
    FOnUnSelectField(Cells[0, Row], '', '', Cells[1, Row], True, False, False);
  Item := FDragItem;
  //Cells[1, Row] := ''; ab fixed 22.04.2004
  Cells[0, Row] := Item.Table.Alias + '.' + Item.Caption;
  if Assigned(FOnSelectField) then
    FOnSelectField(Cells[0, Row], '', '', Cells[1, Row], True, False, False);
end;

procedure TQBDataGrid.CheckField(FieldDef: TQBFieldDef);

  function GetIdentArgument(Arg: TQBFunctionDef): TQBFunctionDef;
  var
    I: integer;
  begin
    Result := nil;
    if Arg.Kind = fkFunction then
    begin
      for I := 0 to Arg.Arguments.Count - 1 do
      begin
        Result := GetIdentArgument(Arg.Arguments[I]);
        if Assigned(Result) then
          Break;
      end;
    end
    else
      Result := Arg;
  end;

var
  I, TekRow: Integer;
  TableAlias: aqbString;
  Arg: TQBFunctionDef;
begin
  if not Assigned(FieldDef) then
    Exit;
  TekRow := RowCount;
  RowCount := RowCount + 1;
  for I := 0 to 1 do
    Cells[I, TekRow] := Cells[I, TekRow - 1];
  //  Cells[1, TekRow - 1] := '';
  //  Cells[2, TekRow - 1] := '';
  TableAlias := FieldDef.TableAlias;
  if Trim(TableAlias) <> '' then
    TableAlias := TableAlias + '.';
  if (FieldDef.Kind = fkFunction) and (Owner is TQBDataPanel) and
    Assigned(TQBDataPanel(Owner).Parser) and
    (TQBDataPanel(Owner).Parser.Aggregates.IndexOf(FieldDef.Name) > -1) then
  begin
    Arg := GetIdentArgument(FieldDef);
    if Assigned(Arg) then
    begin
      if Arg.Name = '*' then
        Cells[0, TekRow - 1] := Arg.Name
      else if Arg.Kind = fkIdentifier then
        Cells[0, TekRow - 1] := TableAlias + Arg.Name // 21.01.04
      else
        Cells[0, TekRow - 1] := Arg.Name;
    end;
    Cells[1, TekRow - 1] := FieldDef.Data;
  end
  else
  begin
    if FieldDef.Kind = fkIdentifier then
      Cells[0, TekRow - 1] := TableAlias + FieldDef.Name
    else
      Cells[0, TekRow - 1] := FieldDef.PureScript;
    Cells[1, TekRow - 1] := FieldDef.Data;
  end;

  // ab 27.11.2003 <<
  {if FieldDef.Alias = '' then
      Cells[0, TekRow - 1] := Cells[2, TekRow - 1]
    else
      Cells[0, TekRow - 1] := FieldDef.Alias;}
  if FieldDef.Alias = '' then
    FieldDef.Alias := FieldDef.Name;
  //  Cells[0, TekRow - 1] := FieldDef.Alias;
  // >> ab 27.11.2003
end;

procedure TQBDataGrid.UnCheckField(FieldDef: TQBFieldDef);
var
  I: Integer;
  TableAlias, FieldName: aqbString;
begin
  if not Assigned(FieldDef) or (FieldDef.Kind <> fkIdentifier) then
    Exit;
  TableAlias := FieldDef.TableAlias;
  if TableAlias <> '' then
    TableAlias := TableAlias + '.';
  FieldName := TableAlias + FieldDef.Name;
  I := 0;
  while I < RowCount do
  begin
    if Cells[0, I] = FieldName then
      DeleteRow(I)
    else
      Inc(I);
  end;
end;

procedure TQBDataGrid.ChangeAlias(const NewName, OldName: aqbString);

  procedure ReplaceAlias(var Value: aqbString; var Change: Boolean);
  var
    PosOf, Len: Integer;
  begin
    PosOf := Pos(OldName + '.', Value);
    while PosOf > 0 do
    begin
      Len := Length(OldName);
      Delete(Value, PosOf, Len);
      Insert(NewName, Value, PosOf);
      PosOf := Pos(OldName + '.', Value);
      Change := true;
    end;
  end;

var
  I: Integer;
  S: aqbString;
  bChange: Boolean;
begin
  if NewName = OldName then
    Exit;
  for I := 1 to RowCount - 1 do
  begin
    bChange := false;
    S := Cells[2, I];
    ReplaceAlias(S, bChange);
    if bChange then
      Cells[2, I] := S;
  end;
  Invalidate;
end;

procedure TQBDataGrid.SetFields(const Value: TaqbStrings);
begin
  if FFields <> Value then
    FFields.Assign(Value);
end;

{$ENDIF}

{ TQBQueryLabel }

procedure TQBQueryLabel.SetText(const Value: aqbString);
var
  I: Integer;
  TextCaption: aqbString;
begin
  FText := Value;
  TextCaption := Value;
  if FText = '' then
    TextCaption := sEmpty;
  I := Length(FText);
  if I > iMaxControlTextLen then
  begin
    TextCaption[iMaxControlTextLen + 1] := '.';
    TextCaption[iMaxControlTextLen + 2] := '.';
    TextCaption[iMaxControlTextLen + 3] := '.';
    Delete(TextCaption, iMaxControlTextLen + 4, I - iMaxControlTextLen - 3);
  end;
  for I := 1 to Length(TextCaption) do
    if (TextCaption[I] = #13) or (TextCaption[I] = #10) then
      TextCaption[I] := ' ';
  Caption := TextCaption;
end;

constructor TQBQueryLabel.Create(AOwner: TComponent);
begin
  inherited;
  Font.Style := [fsUnderline, fsBold];
  Font.Name := 'Arial';
  Font.Color := clNavy;
  Cursor := crQBHand; //crHandPoint; iplus
end;

{ TQBDataPanel }

procedure TQBDataPanel.Clear;
begin
  FGrid.ClearGrid;
  FQueryLabel.Text := '';
end;

constructor TQBDataPanel.Create(AOwner: TComponent);
begin
  if not (AOwner is TWinControl) then
    raise Exception.Create(rsDataInvalidDataParent);
  inherited;
  Parent := AOwner as TWinControl;
  Align := alCLient;
  TabStop := false;

  FPanel := TPanel.Create(Self);
  FPanel.Parent := Self;
  FPanel.Align := alBottom;
  FPanel.Top := 0;
  FPanel.Height := 35;
  FPanel.BevelInner := bvNone;
  FPanel.BevelOuter := bvNone;
  FPanel.BorderStyle := bsNone;

  FDataFromQuery := TLabel.Create(FPanel);
  FDataFromQuery.Parent := FPanel;
  FDataFromQuery.Caption := rsDataFromQuery;
  FDataFromQuery.Top := 3;
  FDataFromQuery.Left := 0;

  FQueryMenu := TPopupMenu.Create(Self);
{$IFDEF VCL5}
  FQueryMenu.AutoHotkeys := maManual;
{$ENDIF}

  FQueryLabel := TQBQueryLabel.Create(FPanel);
  FQueryLabel.Parent := FPanel;
  FQueryLabel.Top := 18;
  FQueryLabel.Left := 10;
  FQueryLabel.Text := '';
  FQueryLabel.OnMouseDown := HandleQueryLabelMouseDown;
  FQueryLabel.PopupMenu := FQueryMenu;

  FGrid := TQBDataGrid.Create(Self);

end;

procedure TQBDataPanel.RefreshFields;
var
  I {, J}: integer;
begin
  Clear;
  if Assigned(FParser) then
  begin
    for I := 0 to FParser.TableDefs.FieldCount - 1 do
      if not (FParser.TableDefs.FieldDefs[I].Scope in QBParamTypes) and
        (Trim(FParser.TableDefs.FieldDefs[I].Name) <> '') then
        FGrid.CheckField(FParser.TableDefs.FieldDefs[I]);
  end;
  if FParser.ValuesItems.IsQuery then
    FQueryLabel.Text := LineExpression(FParser.ValuesItems.Script)
  else
    FQueryLabel.Text := '';

end;

procedure TQBDataPanel.SetParser(const Value: TQBSelectParser);
begin
  if FParser <> Value then
    FParser := Value;
end;

procedure TQBDataPanel.SetDataType(const Value: TQBDataType);
begin
  if FDataType <> Value then
  begin
    FDataType := Value;
    if FDataType = dtInsert then
      FPanel.Visible := True
    else
      FPanel.Visible := False;
  end;
end;

procedure TQBDataPanel.DeleteQuery(Sender: TObject);
begin
{$IFNDEF USE_DEVEXPRESS}
  if MessageBox(Handle, PChar(rsQuerySureWantDelete),
    PChar(rsQueryConfirmation),
    MB_ICONQUESTION or MB_YESNO) = IDNO then
    Exit;
{$ELSE}
  if not SMYesNoMsg(rsQuerySureWantDelete) then
    Exit;
{$ENDIF}
  TFullQueryBuilder(Parent.Parent.Parent.Parent.Parent.Parent).DeleteQueryBuilder
    (TCustomQueryBuilder(FParser.ValuesItems.DataParser.Parent).Name);
end;

procedure TQBDataPanel.HandleQueryLabelMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  QueryBuilder: TCustomQueryBuilder;
  MenuItem: TMenuItem;
begin
  if FParser.ValuesItems.IsQuery then
  begin
    if Button = mbLeft then
      TFullQueryBuilder(Parent.Parent.Parent.Parent.Parent.Parent).SetActiveQueryBuilder
        (TCustomQueryBuilder(FParser.ValuesItems.DataParser.Parent).Name);
    if Button = mbRight then
    begin
{$IFDEF VCL4}
      if FQueryMenu.Items.Count > 0 then
        while FQueryMenu.Items.Count > 0 do
          TCollectionItem(FQueryMenu.Items[FQueryMenu.Items.Count - 1]).Free;
{$ELSE}
      FQueryMenu.Items.Clear;
{$ENDIF}
      MenuItem := TMenuItem.Create(Self);
      MenuItem.Caption := rsQueryDelete;
      MenuItem.OnClick := DeleteQuery;
      FQueryMenu.Items.Add(MenuItem);
    end;
  end
  else
  begin
    if Button = mbLeft then
    begin
      QueryBuilder := TFullQueryBuilder(Parent.Parent.Parent.Parent.Parent.Parent).AddQueryBuilder(False);
      FQueryLabel.Text := '';
      FParser.ValuesItems.IsQuery := True;
      FParser.ValuesItems.DataParser := QueryBuilder.Parser;
    end;
    if Button = mbRight then
    begin
{$IFDEF VCL4}
      if FQueryMenu.Items.Count > 0 then
        while FQueryMenu.Items.Count > 0 do
          TCollectionItem(FQueryMenu.Items[FQueryMenu.Items.Count - 1]).Free;
{$ELSE}
      FQueryMenu.Items.Clear;
{$ENDIF}
    end;
  end;
end;

{$IFDEF USE_DEVEXPRESS}
{ TQBDataGrid }

procedure TQBDataGrid.ClearGrid;
begin
  Clear;
  Add;
end;

procedure TQBDataGrid.ChangeAlias(const NewName, OldName: aqbString);

  procedure ReplaceAlias(var Value: aqbString; var Change: Boolean);
  var
    PosOf, Len: Integer;
  begin
    PosOf := Pos(OldName + '.', Value);
    while PosOf > 0 do
    begin
      Len := Length(OldName);
      Delete(Value, PosOf, Len);
      System.Insert(NewName, Value, PosOf);
      PosOf := Pos(OldName + '.', Value);
      Change := true;
    end;
  end;

var
  I: Integer;
  S: aqbString;
  bChange: Boolean;
begin
  if NewName = OldName then
    Exit;
  for I := 1 to NodesList.Count - 1 do
  begin
    bChange := false;
    S := Nodes[I].Texts[0];
    ReplaceAlias(S, bChange);
    if bChange then
      Nodes[I].Texts[0] := S;
  end;
  Invalidate;
end;

procedure TQBDataGrid.Clear;
begin
  OnDeletion := nil;
  inherited Clear;
  FPrevSrcName := '';
  OnDeletion := HandleDeleteCurrentRow;
end;

constructor TQBDataGrid.Create(AOwner: TComponent);
var
  MenuItem: TMenuItem;
begin
  if not (AOwner is TWinControl) then
    raise Exception.Create(rsSelectOrderInvalidGridParent);
  inherited;
  Parent := AOwner as TWinControl;
  Align := alClient;
  BorderStyle := cxcbsNone;
  OptionsView.ColumnAutoWidth := true;
  OptionsView.GridLines := tlglBoth;
  OptionsView.ShowRoot := False;
  OptionsView.Indicator := True;

  with CreateColumn do
  begin
    Caption.Text := rsDataSourceFieldName;
    Caption.AlignHorz := taCenter;
    PropertiesClass := TcxComboBoxProperties;
    TcxComboBoxProperties(Properties).DropDownListStyle := lsFixedList;
  end;
  with CreateColumn do
  begin
    Caption.Text := rsDataValueOfField;
    Caption.AlignHorz := taCenter;
  end;

  FPopupMenu := TPopupMenu.Create(Self);
{$IFDEF VCL5}
  FPopupMenu.AutoHotkeys := maManual;
{$ENDIF}
  FPopupMenu.AutoPopup := true;
  MenuItem := TMenuItem.Create(Self);
  MenuItem.Caption := rsSelectOrderDeleteCurrentRow;
  MenuItem.OnClick := HandleDeleteRow;
  FPopupMenu.Items.Add(MenuItem);

  PopupMenu := FPopupMenu;

  Add;
  FFields := TaqbStringList.Create();

  OnEditing := HandleEditing;
  OnEdited := HandleEdited;
  OnAfterSorting := HandleAfterSorting;
  OnDeletion := HandleDeleteCurrentRow;
  OnDragOver := HandleDragOver;
  OnDragDrop := HandleDragDrop;
end;

destructor TQBDataGrid.Destroy;
begin
  FFields.Free();
  OnDeletion := nil;
  OnEditing := nil;
  OnEdited := nil;
  OnAfterSorting := nil;
  CancelEdit;
  inherited Destroy();
end;

procedure TQBDataGrid.HandleAfterSorting(Sender: TObject);
begin
  if TopNode = nil then
    Exit;
  if (TopNode.Texts[0] = '') and (TopNode.Texts[1] = '') then
    TopNode.MoveTo(LastNode, tlamAdd);
end;

procedure TQBDataGrid.HandleDeleteCurrentRow(Sender: TObject;
  ANode: TcxTreeListNode);
var
  FieldName, Data: aqbString;
  I: integer;
  Found: boolean;
begin
  if ANode = nil then
    Exit;
  if ANode.IsLast then
  begin
    Add;
    Exit;
  end;
  Found := False;
  for I := 0 to Nodes.Count - 2 do
  begin
    Found := (I <> ANode.Index) and (ANode.Texts[0] = Nodes[I].Texts[0]);
    if Found then
      Break;
  end;
  FieldName := ANode.Texts[0];
  Data := ANode.Texts[1];
  if Assigned(FOnDeleteField) then
    FOnDeleteField(FieldName, '', '', Data, not Found, False, False)
  else if ANode <> nil then
    ANode.Delete;
end;

procedure TQBDataGrid.HandleDeleteRow(Sender: TObject);
begin
  if FocusedNode.IsLast then
    Exit;
  HandleDeleteCurrentRow(nil, FocusedNode);
  FocusedNode.Delete;
end;

procedure TQBDataGrid.HandleDragDrop(Sender, Source: TObject; X,
  Y: Integer);
var
  Item: TQBListItem;
  Node: TcxTreeListNode;
begin

  Node := HitTest.HitNode;
  if (Node = nil) or ((Node <> nil) and (Node.IsLast)) then
  begin
    Node := LastNode;
    Add;
  end;

  if Source = Sender then
  begin
    Exit;
  end;
  if (HitTest.HitNode <> nil) and (not HitTest.HitNode.IsLast) then
    if Assigned(FOnUnSelectField) then
      FOnUnSelectField(Node.Texts[0], '', '', Node.Texts[1], True, False, False);
  Item := FDragItem;
  Node.Texts[0] := Item.Table.Alias + '.' + Item.Caption;
  Node.Texts[1] := '';
  Node.Focused := true;
  if Assigned(FOnSelectField) then
    FOnSelectField(Node.Texts[0], '', '', Node.Texts[1], True, False, False);
  HandleAfterSorting(Self);
end;

procedure TQBDataGrid.HandleDragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
var
  Tbl: TQBFloatObject;
begin
  Accept := false;
  if not (Source is TQBWorkArea) then
    Exit;
  Tbl := TQBFloatObject(TQBWorkArea(Source).SelectionObject);
  if not (Tbl is TQBTable) then
    Exit;
  FDragItem := (Tbl as TQBTable).CurrentItem;
  if FDragItem = nil then
    Exit;
  Accept := true;
end;

procedure TQBDataGrid.HandleEdited(Sender: TObject;
  AColumn: TcxTreeListColumn);
var
  I: integer;
  Found: boolean;
  Node: TcxTreeListNode;

  //  TableName, FieldName: aqbString;
  //  TableDef: TQBTableDef;
  //  FieldDef: TQBFieldDef;
  //  PrevAbsIndex : integer;
begin
  Node := FocusedNode;
  if Node = nil then
    Exit;

  if AColumn.Caption.Text = rsDataSourceFieldName then
  begin
    if (FPrevSrcName = Node.Texts[0]) and (FPrevSrcName <> '') then
      Exit;
      
    Found := False;
    for I := 0 to Nodes.Count - 1 do
    begin
      Found := (I <> Node.Index) and (Nodes[I].Texts[0] = Node.Texts[0])
        and (Trim(Node.Texts[0]) <> '');
      if Found then
      begin
        Node.Texts[0] := FPrevSrcName;
        Exit;
      end;  
    end;

    {
    TableName := ExtractTableName(FPrevSrcName, TQBDataPanel(Parent).Parser.Scanner.IdentQuote,
       TQBDataPanel(Parent).Parser.Scanner.GetQuotePair(TQBDataPanel(Parent).Parser.Scanner.IdentQuote));
    FieldName := ExtractFieldName(FPrevSrcName, TQBDataPanel(Parent).Parser.Scanner.IdentQuote,
         TQBDataPanel(Parent).Parser.Scanner.GetQuotePair(TQBDataPanel(Parent).Parser.Scanner.IdentQuote));
    TableDef := FParser.TableDefs.FindByAlias(TableName);
    if TableDef <> nil then
    begin
      FieldDef := TableDef.FieldDefs.FindByName(FieldName);
      if FieldDef <> nil then
      begin

      end;
    end;
    }
    if Assigned(FOnUnselectField) then
      FOnUnselectField(FPrevSrcName, '', '', Node.Texts[1], not Found, False, False);
    if Assigned(FOnSelectField) then
      FOnSelectField(Node.Texts[0], '', '', Node.Texts[1], True, False, False);
  end;
  if Assigned(FOnChangeFieldData) then
    FOnChangeFieldData(Node.Texts[0], Node.Texts[1]);

  if Node.IsLast and (Node.Texts[0] <> '') then
    Add;
  if (not Node.IsLast) and (Node.Texts[0] = '') then
    Node.Delete;
end;

procedure TQBDataGrid.HandleEditing(Sender: TObject;
  AColumn: TcxTreeListColumn; var Allow: Boolean);
begin
  if AColumn.Caption.Text = rsDataSourceFieldName then
  begin
    (AColumn.Properties as TcxComboBoxProperties).Items.Assign(FFields);
    FPrevSrcName := FocusedNode.Texts[0];
  end;
end;

procedure TQBDataGrid.SetFields(const Value: TaqbStrings);
begin
  if FFields <> Value then
    FFields.Assign(Value);
end;

procedure TQBDataGrid.UnCheckField(FieldDef: TQBFieldDef);
var
  I: Integer;
  TableAlias, FieldName: aqbString;
begin
  if not Assigned(FieldDef) or (FieldDef.Kind <> fkIdentifier) then
    Exit;
  TableAlias := FieldDef.TableAlias;
  if TableAlias <> '' then
    TableAlias := TableAlias + '.';
  FieldName := TableAlias + FieldDef.Name;
  I := 0;
  while I < Nodes.Count - 1 do
  begin
    if Nodes[I].Texts[0] = FieldName then
      Nodes[I].Delete
    else
      Inc(I);
  end;
end;

procedure TQBDataGrid.CheckField(FieldDef: TQBFieldDef);

  function GetIdentArgument(Arg: TQBFunctionDef): TQBFunctionDef;
  var
    I: integer;
  begin
    Result := nil;
    if Arg.Kind = fkFunction then
    begin
      for I := 0 to Arg.Arguments.Count - 1 do
      begin
        Result := GetIdentArgument(Arg.Arguments[I]);
        if Assigned(Result) then
          Break;
      end;
    end
    else
      Result := Arg;
  end;

var
  TableAlias: aqbString;
  Arg: TQBFunctionDef;
  Node: TcxTreeListNode;
begin
  if not Assigned(FieldDef) then
    Exit;
  Node := LastNode;
  Add;
  //  HandleAfterSorting(Self);
  TableAlias := FieldDef.TableAlias;
  if Trim(TableAlias) <> '' then
    TableAlias := TableAlias + '.';
  if (FieldDef.Kind = fkFunction) and (Owner is TQBDataPanel) and
    Assigned(TQBDataPanel(Owner).Parser) and
    (TQBDataPanel(Owner).Parser.Aggregates.IndexOf(FieldDef.Name) > -1) then
  begin
    Arg := GetIdentArgument(FieldDef);
    if Assigned(Arg) then
    begin
      if Arg.Name = '*' then
        Node.Texts[0] := Arg.Name
      else if Arg.Kind = fkIdentifier then
        Node.Texts[0] := TableAlias + Arg.Name // 21.01.04
      else
        Node.Texts[0] := Arg.Name;
    end;
    Node.Texts[1] := FieldDef.Data;
  end
  else
  begin
    if FieldDef.Kind = fkIdentifier then
      Node.Texts[0] := TableAlias + FieldDef.Name
    else
      Node.Texts[0] := FieldDef.PureScript;
    Node.Texts[1] := FieldDef.Data;
  end;
  // ab 27.11.2003 <<
  {if FieldDef.Alias = '' then
      Cells[0, TekRow - 1] := Cells[2, TekRow - 1]
    else
      Cells[0, TekRow - 1] := FieldDef.Alias;}
  if FieldDef.Alias = '' then
    FieldDef.Alias := FieldDef.Name;
end;

{$ENDIF}

end.
